package main;

import java.io.File;
import java.util.concurrent.ExecutionException;
import swingExtended.swingWorkers.ProgressUpdate;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CancellationException;
import main.errorUpdate.ErrorUpdate;
import main.textUpdate.OutputUpdate;
import ngram.exception.NoNGramFilesFoundException;
import processorIO.FilePath;
import swingExtended.EstimatingProgressBar;
import swingExtended.SwingExtended;
import swingExtended.progressPanel.ProgressPanel;
import swingExtended.swingWorkers.GenericUpdateWorker;

/**
 *
 * @author Shimu
 * @date 24-Feb-2013
 */
public abstract class NGramWorker extends GenericUpdateWorker<Void, ProgressUpdate> {

    protected final ProgressPanel PANEL;

    private final EstimatingProgressBar PROGRESS_BAR;

    public static final int MIN_GRAM = 1;

    public static final int MAX_GRAM = 5;
    
    protected NGramWorker(ProgressPanel panel, EstimatingProgressBar progressBar) {
        this.PANEL = panel;
        this.PROGRESS_BAR = progressBar;
    }

    protected NGramWorker(ProgressPanel panel) {
        this(panel, panel.getProgressBar());
    }

    /**
     * Given the name of a file that contains "google", process that file.
     * The process should attempt to terminate as soon as possible when
     * the status is Status.REQUEST_STOP.
     * 
     * @param file
     * @throws Exception 
     */
    protected abstract void process(String file) throws Exception;

    protected abstract String getHeader();

    /**
     * Called in doInBackground.
     * 
     * @return
     * @throws IOException
     * @throws NoNGramFilesFoundException 
     */
    protected abstract List<String> initFiles() throws IOException, NoNGramFilesFoundException;
        
    protected void publishException(String errorMsg,
            Exception ex, boolean showDialog) {
        publish(new ErrorUpdate(PANEL, errorMsg, ex));
        // We WANT the dialog to block the current progress, so we do
        // NOT publish it.
        if (showDialog) {
            SwingExtended.openWarningWindow(PANEL, errorMsg, ex);
        }
    }

    @Override
    public final Void doInBackgroundHelper() throws Exception {
        publish(new OutputUpdate(PANEL, getHeader()));
        
        List<String> files = null;
        try {
            files = initFiles();
        } catch (IOException | NoNGramFilesFoundException ex) {
            publishException("", ex, true);
            return null;
        }

        long totalFileSize = 0;
        for(String file : files) {
            totalFileSize += new File(file).length();
        }
        final int max = (int) (totalFileSize / 1048576.0);
        publish(new ProgressUpdate() {
            @Override
            public void update() {
                PROGRESS_BAR.setMaximum(max);                
            }
        });

        for (final String f : files) {
            if (isCancelled()) {
                break;
            }
            // Size of the current file (in MB)
            final double fileSize = new File(f).length() / 1048576.0;
            publish(new ProgressUpdate(){
                @Override
                public void update() {
                    PANEL.setStatusText(String.format("%s (%.2f MB)", 
                            FilePath.getName(f), fileSize));
                }
            });
            try {
                process(f);
            } catch (Exception ex) {
                publish(new ErrorUpdate(PANEL, String.format(
                    "An unexpected error occurred while processing: %s.\n"
                    + "Will try to move onto the next file.\n", new File(f).getName()), ex));                
            }
            publish(new ProgressUpdate() {
                @Override
                public void update() {
                    PROGRESS_BAR.incrementValue(fileSize);  
                    PANEL.setSpeedText(String.format("%.4f MB/s", PROGRESS_BAR.getRate() * 1000));
                    PROGRESS_BAR.validate();
                }
            });
        }
        return null;
    }

    @Override
    protected void done() {
        super.done();
        try {
            get();
        } catch (InterruptedException ex) {
            System.err.println("interrupted!");
        } catch (ExecutionException ex) {
            SwingExtended.openWarningWindow(PANEL, "Unexpected error occurred", ex);
            ex.printStackTrace();
        } catch (CancellationException ex) {
            // Do nothing, user is allowed to cancel execution
        }
    }
}
